package net.simflow.swf.analyzer.gui;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map.Entry;

import net.simflow.swf.analyzer.opt.FontDataClone;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.wb.swt.SWTResourceManager;

public abstract class ConfigDialog extends Dialog {

	private HashMap<String, Composite> binding;
	private LinkedHashMap<String, ArrayList<String>> tree;

	protected Shell shell;
	protected Object result;
	private Label lblTitle;
	private Tree treeLeft;
	private Composite cmpContent;

	private Point size;

	/**
	 * Create the shell.
	 * 
	 * @param display
	 */
	public ConfigDialog(Shell parent, String title, Point size) {
		super(parent, SWT.CLOSE | SWT.MIN | SWT.MAX | SWT.TITLE);
		setText(title);
		this.size = size;
	}

	/**
	 * Open the dialog.
	 * 
	 * @return the result
	 */
	public Object open() {
		createContents();
		binding = getBinding();
		tree = getTree();
		if (binding != null) {
			fillContents(tree, binding);
		}
		shell.open();
		shell.layout();
		Display display = getParent().getDisplay();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
		return result;
	}

	/**
	 * Create contents of the shell.
	 */
	protected void createContents() {

		shell = new Shell(getParent(), SWT.CLOSE | SWT.MIN | SWT.MAX
				| SWT.TITLE | SWT.APPLICATION_MODAL);
		shell.setSize(size);
		shell.setText(getText());

		shell.addListener(SWT.Traverse, new Listener() {
			public void handleEvent(Event e) {
				if (e.detail == SWT.TRAVERSE_ESCAPE) {
					e.doit = false;
				}
			}
		});

		int parlocx = shell.getParent().getLocation().x;
		int parlocy = shell.getParent().getLocation().y;
		int parw = shell.getParent().getSize().x;
		int parh = shell.getParent().getSize().y;
		int thisw = shell.getSize().x;
		int thish = shell.getSize().y;
		int locx = parw / 2 + parlocx - thisw / 2;
		int locy = parh / 2 + parlocy - thish / 2;
		shell.setLocation(locx, locy);

		GridLayout gridLayout = new GridLayout(1, false);
		gridLayout.verticalSpacing = 0;
		gridLayout.marginWidth = 0;
		gridLayout.horizontalSpacing = 0;
		gridLayout.marginHeight = 0;
		shell.setLayout(gridLayout);

		Composite cmpMain = new Composite(shell, SWT.NONE);
		GridLayout gl_cmpMain = new GridLayout(3, false);
		gl_cmpMain.horizontalSpacing = 0;
		gl_cmpMain.verticalSpacing = 0;
		gl_cmpMain.marginWidth = 0;
		gl_cmpMain.marginHeight = 0;
		cmpMain.setLayout(gl_cmpMain);
		cmpMain.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));

		Composite cmpLeft = new Composite(cmpMain, SWT.NONE);
		cmpLeft.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
		FillLayout fl_cmpLeft = new FillLayout(SWT.HORIZONTAL);
		fl_cmpLeft.marginWidth = 10;
		fl_cmpLeft.marginHeight = 10;
		cmpLeft.setLayout(fl_cmpLeft);
		GridData gd_cmpLeft = new GridData(SWT.FILL, SWT.FILL, false, true, 1,
				1);
		gd_cmpLeft.widthHint = 212;
		cmpLeft.setLayoutData(gd_cmpLeft);

		treeLeft = new Tree(cmpLeft, SWT.NONE);
		treeLeft.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				TreeItem item = treeLeft.getSelection()[0];
				Composite ocmp = binding.get(item.getText());

				TreeItem pItem = item.getParentItem();
				String title;
				if (pItem != null) {
					title = pItem.getText() + ": " + item.getText();
				} else {
					title = item.getText();
				}
				lblTitle.setText(title);

				if (ocmp != null) {
					((GridData) ocmp.getLayoutData()).exclude = false;
					ocmp.setVisible(true);
				}
				for (Composite cmp : binding.values()) {
					if (cmp != ocmp) {
						((GridData) cmp.getLayoutData()).exclude = true;
						cmp.setVisible(false);
					}
				}
				cmpContent.layout();
			}
		});

		Label lineMain = new Label(cmpMain, SWT.SEPARATOR | SWT.VERTICAL);
		lineMain.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, true, 1,
				1));

		Composite cmpRight = new Composite(cmpMain, SWT.NONE);
		GridLayout gl_cmpRight = new GridLayout(1, false);
		gl_cmpRight.verticalSpacing = 0;
		gl_cmpRight.marginWidth = 0;
		gl_cmpRight.marginHeight = 0;
		gl_cmpRight.horizontalSpacing = 0;
		cmpRight.setLayout(gl_cmpRight);
		cmpRight.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1,
				1));

		Composite cmpTitle = new Composite(cmpRight, SWT.NONE);
		cmpTitle.setLayout(new GridLayout(1, false));
		GridData gd_cmpTitle = new GridData(SWT.FILL, SWT.FILL, true, false, 1,
				1);
		gd_cmpTitle.heightHint = 40;
		cmpTitle.setLayoutData(gd_cmpTitle);

		Composite cmpTitleContent = new Composite(cmpTitle, SWT.NONE);
		cmpTitleContent.setLayout(new GridLayout(1, false));
		cmpTitleContent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
				true, 1, 1));

		lblTitle = new Label(cmpTitleContent, SWT.NONE);
		lblTitle.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1,
				1));
		FontData fontData = FontDataClone.clone(Display.getCurrent()
				.getSystemFont().getFontData()[0]);
		fontData.setHeight(fontData.getHeight() + 1);
		fontData.setStyle(SWT.BOLD);
		Font font = new Font(Display.getCurrent(), fontData);
		lblTitle.setFont(font);

		Label lineRight = new Label(cmpRight, SWT.SEPARATOR | SWT.HORIZONTAL);
		lineRight.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false,
				1, 1));

		cmpContent = new Composite(cmpRight, SWT.NONE);
		cmpContent.setLayout(new GridLayout(1, false));
		cmpContent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true,
				1, 1));

		Label line = new Label(shell, SWT.SEPARATOR | SWT.HORIZONTAL);
		line.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));

		Composite cmpBottom = new Composite(shell, SWT.NONE);
		GridLayout gl_cmpBottom = new GridLayout(2, false);
		gl_cmpBottom.marginWidth = 0;
		gl_cmpBottom.marginHeight = 10;
		cmpBottom.setLayout(gl_cmpBottom);
		cmpBottom.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false,
				1, 1));

		Composite cmpButtonBlank = new Composite(cmpBottom, SWT.NONE);
		GridData gd_cmpButtonBlank = new GridData(SWT.FILL, SWT.FILL, true,
				false, 1, 1);
		gd_cmpButtonBlank.heightHint = 15;
		cmpButtonBlank.setLayoutData(gd_cmpButtonBlank);
		cmpButtonBlank.setBounds(0, 0, 64, 64);

		Composite cmpButton = new Composite(cmpBottom, SWT.NONE);
		cmpButton.setLayout(new FillLayout(SWT.HORIZONTAL));
		GridData gd_cmpButton = new GridData(SWT.FILL, SWT.CENTER, false,
				false, 1, 1);
		gd_cmpButton.widthHint = 334;
		cmpButton.setLayoutData(gd_cmpButton);

		Button btnOk = new Button(cmpButton, SWT.NONE);
		btnOk.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				save();
				exit();
			}
		});
		btnOk.setText("OK");

		Button btnSave = new Button(cmpButton, SWT.NONE);
		btnSave.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				save();
			}
		});
		btnSave.setText("Save");

		Button btnCancel = new Button(cmpButton, SWT.NONE);
		btnCancel.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				exit();
			}
		});
		btnCancel.setText("Cancel");
	}

	abstract protected HashMap<String, Composite> getBinding();

	abstract protected LinkedHashMap<String, ArrayList<String>> getTree();

	private void fillContents(LinkedHashMap<String, ArrayList<String>> tree,
			HashMap<String, Composite> binding) {
		ArrayList<String> list = new ArrayList<String>();
		for (Entry<String, ArrayList<String>> en : tree.entrySet()) {
			String name = en.getKey();
			list.add(name);
			TreeItem item = new TreeItem(treeLeft, SWT.NONE);
			item.setText(name);

			ArrayList<String> l = en.getValue();
			if (l != null) {
				for (String n : l) {
					list.add(n);
					TreeItem it = new TreeItem(item, SWT.NONE);
					it.setText(n);
				}
			}
			item.setExpanded(true);
		}

		for (String name : list) {
			Composite cmp = binding.get(name);
			if (cmp != null) {
				cmp.setParent(cmpContent);
				GridData gd_cmp = new GridData(SWT.FILL, SWT.FILL, true, true,
						1, 1);
				gd_cmp.exclude = true;
				cmp.setLayoutData(gd_cmp);
			}
		}
	}

	abstract protected void save();

	private void exit() {
		shell.dispose();
	}

	@Override
	protected void checkSubclass() {
		// Disable the check that prevents subclassing of SWT components
	}
}
